// HSS.Forms.Docking.DockPaneStrip.cs
// ----------------------------------------------------------------------------
// Licensed under the MIT license
// http://www.opensource.org/licenses/mit-license.html
// ----------------------------------------------------------------------------
// HighSpeed-Solutions, LLC
// Copyright (c) 2001-2010
// ----------------------------------------------------------------------------
// File:       DockPaneStrip.cs
// Author:     HSS\gbanta
// Created:    08/12/2010
// Modified:   12/24/2010
// ----------------------------------------------------------------------------
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace HSS.Forms.Docking
{
	internal class DockPaneStrip : DockPaneStripBase
	{
		#region PaneTab
		private class PaneTab : Tab
		{
			public PaneTab(IDockContent content)
				: base(content)
			{
			}

			private int _tabX;
			public int TabX
			{
				get { return _tabX; }
				set { _tabX = value; }
			}

			private int _tabWidth;
			public int TabWidth
			{
				get { return _tabWidth; }
				set { _tabWidth = value; }
			}

			private int _maxWidth;
			public int MaxWidth
			{
				get { return _maxWidth; }
				set { _maxWidth = value; }
			}

			private bool _flag;
			protected internal bool Flag
			{
				get { return _flag; }
				set { _flag = value; }
			}
		}
		protected internal override DockPaneStripBase.Tab CreateTab(IDockContent content)
		{
			return new PaneTab(content);
		}
		#endregion

		#region InertButton
		private sealed class InertButton : InertButtonBase
		{
			private Bitmap _image0, _image1;

			public InertButton(Bitmap image0, Bitmap image1)
				: base()
			{
				_image0 = image0;
				_image1 = image1;
			}

			private int _imageCategory = 0;
			public int ImageCategory
			{
				get { return _imageCategory; }
				set
				{
					if (_imageCategory == value)
						return;

					_imageCategory = value;
					Invalidate();
				}
			}

			public override Bitmap Image
			{
				get { return ImageCategory == 0 ? _image0 : _image1; }
			}

			protected override void OnRefreshChanges()
			{
				if (DockPaneStrip.ColorDocumentActiveText != ForeColor)
				{
					ForeColor = DockPaneStrip.ColorDocumentActiveText;
					Invalidate();
				}
			}
		}
		#endregion

		#region Consts
		private const int _ToolWindowStripGapTop = 0;
		private const int _ToolWindowStripGapBottom = 1;
		private const int _ToolWindowStripGapLeft = 0;
		private const int _ToolWindowStripGapRight = 0;
		private const int _ToolWindowImageHeight = 16;
		private const int _ToolWindowImageWidth = 16;
		private const int _ToolWindowImageGapTop = 2;
		private const int _ToolWindowImageGapBottom = 2;
		private const int _ToolWindowImageGapLeft = 2;
		private const int _ToolWindowImageGapRight = 0;
		private const int _ToolWindowTextGapRight = 0;
		private const int _ToolWindowTabSeperatorGapTop = 3;
		private const int _ToolWindowTabSeperatorGapBottom = 3;


		private const int _DocumentStripGapTop = 0;
		private const int _DocumentStripGapBottom = 0;

		private const int _DocumentButtonGapTop = 2;
		private const int _DocumentButtonGapBottom = 4;
		private const int _DocumentButtonGapBetween = 0;
		private const int _DocumentButtonGapRight = 2;

		private const int _DocumentTabMaxWidth = 200;
		private const int _DocumentTabGapTop = 1;
		private const int _DocumentTabGapLeft = 0;
		private const int _DocumentTabGapRight = 0;

		private const int _DocumentIconGapBottom = 1;
		private const int _DocumentIconGapLeft = 8;
		private const int _DocumentIconGapRight = 0;
		private const int _DocumentIconHeight = 16;
		private const int _DocumentIconWidth = 16;

		private const int _DocumentTextGapLeft = 6;
		private const int _DocumentTextGapRight = 8;
		#endregion

		private static Bitmap _imageButtonClose;
		private static Bitmap ImageButtonClose
		{
			get
			{
				if (_imageButtonClose == null)
					_imageButtonClose = Resources.DockPane_Close;

				return _imageButtonClose;
			}
		}

		private InertButton _buttonClose;
		private InertButton ButtonClose
		{
			get
			{
				if (_buttonClose == null)
				{
					_buttonClose = new InertButton(ImageButtonClose, ImageButtonClose);
					_toolTip.SetToolTip(_buttonClose, ToolTipClose);
					_buttonClose.Click += new EventHandler(Close_Click);
					Controls.Add(_buttonClose);
				}

				return _buttonClose;
			}
		}

		private static Bitmap _imageButtonWindowList;
		private static Bitmap ImageButtonWindowList
		{
			get
			{
				if (_imageButtonWindowList == null)
					_imageButtonWindowList = Resources.DockPane_Option;

				return _imageButtonWindowList;
			}
		}

		private static Bitmap _imageButtonWindowListOverflow;
		private static Bitmap ImageButtonWindowListOverflow
		{
			get
			{
				if (_imageButtonWindowListOverflow == null)
					_imageButtonWindowListOverflow = Resources.DockPane_OptionOverflow;

				return _imageButtonWindowListOverflow;
			}
		}

		private InertButton _buttonWindowList;
		private InertButton ButtonWindowList
		{
			get
			{
				if (_buttonWindowList == null)
				{
					_buttonWindowList = new InertButton(ImageButtonWindowList, ImageButtonWindowListOverflow);
					_toolTip.SetToolTip(_buttonWindowList, ToolTipSelect);
					_buttonWindowList.Click += new EventHandler(WindowList_Click);
					Controls.Add(_buttonWindowList);
				}

				return _buttonWindowList;
			}
		}

		private static GraphicsPath GraphicsPath
		{
			get { return AutoHideStrip.GraphicsPath; }
		}

		private IContainer _components;
		private ToolTip _toolTip;
		private IContainer Components
		{
			get { return _components; }
		}

		#region Customizable Properties
		private static int ToolWindowStripGapTop
		{
			get { return _ToolWindowStripGapTop; }
		}

		private static int ToolWindowStripGapBottom
		{
			get { return _ToolWindowStripGapBottom; }
		}

		private static int ToolWindowStripGapLeft
		{
			get { return _ToolWindowStripGapLeft; }
		}

		private static int ToolWindowStripGapRight
		{
			get { return _ToolWindowStripGapRight; }
		}

		private static int ToolWindowImageHeight
		{
			get { return _ToolWindowImageHeight; }
		}

		private static int ToolWindowImageWidth
		{
			get { return _ToolWindowImageWidth; }
		}

		private static int ToolWindowImageGapTop
		{
			get { return _ToolWindowImageGapTop; }
		}

		private static int ToolWindowImageGapBottom
		{
			get { return _ToolWindowImageGapBottom; }
		}

		private static int ToolWindowImageGapLeft
		{
			get { return _ToolWindowImageGapLeft; }
		}

		private static int ToolWindowImageGapRight
		{
			get { return _ToolWindowImageGapRight; }
		}

		private static int ToolWindowTextGapRight
		{
			get { return _ToolWindowTextGapRight; }
		}

		private static int ToolWindowTabSeperatorGapTop
		{
			get { return _ToolWindowTabSeperatorGapTop; }
		}

		private static int ToolWindowTabSeperatorGapBottom
		{
			get { return _ToolWindowTabSeperatorGapBottom; }
		}

		private static string _toolTipClose;
		private static string ToolTipClose
		{
			get
			{
				if (_toolTipClose == null)
					_toolTipClose = Strings.DockPaneStrip_ToolTipClose;
				return _toolTipClose;
			}
		}

		private static string _toolTipSelect;
		private static string ToolTipSelect
		{
			get
			{
				if (_toolTipSelect == null)
					_toolTipSelect = Strings.DockPaneStrip_ToolTipWindowList;
				return _toolTipSelect;
			}
		}

		private TextFormatFlags ToolWindowTextFormat
		{
			get
			{
				TextFormatFlags textFormat = TextFormatFlags.EndEllipsis |
					TextFormatFlags.Top |
					TextFormatFlags.SingleLine;
				if (RightToLeft == RightToLeft.Yes)
					return textFormat | TextFormatFlags.RightToLeft | TextFormatFlags.Right;
				else
					return textFormat;
			}
		}

		private static int DocumentStripGapTop
		{
			get { return _DocumentStripGapTop; }
		}

		private static int DocumentStripGapBottom
		{
			get { return _DocumentStripGapBottom; }
		}

		private TextFormatFlags DocumentTextFormat
		{
			get
			{
				TextFormatFlags textFormat = TextFormatFlags.PathEllipsis |
				   TextFormatFlags.SingleLine |
				   TextFormatFlags.VerticalCenter |
				   TextFormatFlags.PreserveGraphicsClipping |
				   TextFormatFlags.HorizontalCenter;
				if (RightToLeft == RightToLeft.Yes)
					return textFormat | TextFormatFlags.RightToLeft;
				else
					return textFormat;
			}
		}

		private static int DocumentTabMaxWidth
		{
			get { return _DocumentTabMaxWidth; }
		}

		private static int DocumentButtonGapTop
		{
			get { return _DocumentButtonGapTop; }
		}

		private static int DocumentButtonGapBottom
		{
			get { return _DocumentButtonGapBottom; }
		}

		private static int DocumentButtonGapBetween
		{
			get { return _DocumentButtonGapBetween; }
		}

		private static int DocumentButtonGapRight
		{
			get { return _DocumentButtonGapRight; }
		}

		private static int DocumentTabGapTop
		{
			get { return _DocumentTabGapTop; }
		}

		private static int DocumentTabGapLeft
		{
			get { return _DocumentTabGapLeft; }
		}

		private static int DocumentTabGapRight
		{
			get { return _DocumentTabGapRight; }
		}

		private static int DocumentIconGapBottom
		{
			get { return _DocumentIconGapBottom; }
		}

		private static int DocumentIconGapLeft
		{
			get { return _DocumentIconGapLeft; }
		}

		private static int DocumentIconGapRight
		{
			get { return _DocumentIconGapRight; }
		}

		private static int DocumentIconWidth
		{
			get { return _DocumentIconWidth; }
		}

		private static int DocumentIconHeight
		{
			get { return _DocumentIconHeight; }
		}

		private static int DocumentTextGapRight
		{
			get { return _DocumentTextGapRight; }
		}

		private static Pen PenToolWindowTabBorder
		{
			get { return SystemPens.GrayText; }
		}

		private static Pen PenDocumentTabActiveBorder
		{
			get
			{
				return new Pen(Color.FromArgb(135, 180, 197));
				//return SystemPens.ControlDarkDark;
			}
		}

		private static Pen PenDocumentTabInactiveBorder
		{
			get { return SystemPens.GrayText; }
		}


		private static Brush DocTabActive_Brush(Rectangle rect)
		{
			return new LinearGradientBrush(rect, Color.White, DockPanel.Instance.DocumentTabActiveFillColor, LinearGradientMode.Vertical);
		}

		private static Brush DocTabInactive_Brush(Rectangle rect)
		{
			return new LinearGradientBrush(rect, Color.GhostWhite, DockPanel.Instance.DocumentTabInactiveFillColor, LinearGradientMode.Vertical);
		}


		private static Brush BrushToolWindowActiveBackground(Rectangle rect)
		{
			return new LinearGradientBrush(rect, Color.White, SystemColors.ControlLightLight, LinearGradientMode.Vertical);
		}

		private static Brush BrushToolWindowInactiveBackground(Rectangle rect)
		{
			return new LinearGradientBrush(rect, Color.LightGray, Color.White, LinearGradientMode.Vertical);
		}

		private static Color ColorToolWindowActiveText
		{
			get { return SystemColors.ControlText; }
		}

		private static Color ColorDocumentActiveText
		{
			get { return SystemColors.ControlText; }
		}

		private static Color ColorToolWindowInactiveText
		{
			get { return SystemColors.ControlDarkDark; }
		}

		private static Color ColorDocumentInactiveText
		{
			get { return SystemColors.ControlText; }
		}

		#endregion

		public DockPaneStrip(DockPane pane)
			: base(pane)
		{
			SetStyle(ControlStyles.ResizeRedraw |
				ControlStyles.UserPaint |
				ControlStyles.AllPaintingInWmPaint |
				ControlStyles.OptimizedDoubleBuffer, true);

			this.DoubleBuffered = true;
			SuspendLayout();

			_components = new Container();
			_toolTip = new ToolTip(Components);
			_selectMenu = new ContextMenuStrip(Components);

			ResumeLayout();
		}

		protected override void Dispose(bool disposing)
		{
			if (disposing)
			{
				Components.Dispose();
				if (_boldFont != null)
				{
					_boldFont.Dispose();
					_boldFont = null;
				}
			}
			base.Dispose(disposing);
		}

		private static Font TextFont
		{
			get { return SystemInformation.MenuFont; }
		}

		private Font _font;
		private Font _boldFont;
		private Font BoldFont
		{
			get
			{
				if (IsDisposed)
					return null;

				if (_boldFont == null)
				{
					_font = TextFont;
					_boldFont = new Font(TextFont, FontStyle.Bold);
				}
				else if (_font != TextFont)
				{
					_boldFont.Dispose();
					_font = TextFont;
					_boldFont = new Font(TextFont, FontStyle.Bold);
				}

				return _boldFont;
			}
		}

		private int _startDisplayingTab = 0;
		private int StartDisplayingTab
		{
			get { return _startDisplayingTab; }
			set
			{
				_startDisplayingTab = value;
				Invalidate();
			}
		}

		private int _endDisplayingTab = 0;
		private int EndDisplayingTab
		{
			get { return _endDisplayingTab; }
			set { _endDisplayingTab = value; }
		}

		private bool _documentTabsOverflow = false;
		private bool DocumentTabsOverflow
		{
			set
			{
				if (_documentTabsOverflow == value)
					return;

				_documentTabsOverflow = value;
				if (value)
					ButtonWindowList.ImageCategory = 1;
				else
					ButtonWindowList.ImageCategory = 0;
			}
		}

		protected internal override int MeasureHeight()
		{
			if (Appearance == DockPane.AppearanceStyle.ToolWindow)
				return MeasureHeight_ToolWindow();
			else
				return MeasureHeight_Document();
		}

		private int MeasureHeight_ToolWindow()
		{
			if (DockPane.IsAutoHide || Tabs.Count <= 1)
				return 0;

			int height = Math.Max(TextFont.Height, ToolWindowImageHeight + ToolWindowImageGapTop + ToolWindowImageGapBottom)
				+ ToolWindowStripGapTop + ToolWindowStripGapBottom;

			return height + 3;
		}

		private int MeasureHeight_Document()
		{
			int height = Math.Max(TextFont.Height + DocumentTabGapTop,
				ButtonClose.Height + DocumentButtonGapTop + DocumentButtonGapBottom)
				+ DocumentStripGapBottom + DocumentStripGapTop;

			return height;
		}

		protected override void OnPaint(PaintEventArgs e)
		{
			if (this.BackColor != DockPanel.Instance.EnvironmentBackColor)
				this.BackColor = DockPanel.Instance.EnvironmentBackColor;
			base.OnPaint(e);
			CalculateTabs();
			if (Appearance == DockPane.AppearanceStyle.Document && DockPane.ActiveContent != null)
			{
				if (EnsureDocumentTabVisible(DockPane.ActiveContent, false))
					CalculateTabs();
			}

			DrawTabStrip(e.Graphics);
		}

		protected override void OnRefreshChanges()
		{
			SetInertButtons();
			Invalidate();
		}

		protected internal override GraphicsPath GetOutline(int index)
		{

			if (Appearance == DockPane.AppearanceStyle.Document)
				return GetOutline_Document(index);
			else
				return GetOutline_ToolWindow(index);

		}

		private GraphicsPath GetOutline_Document(int index)
		{
			Rectangle rectTab = GetTabRectangle(index);
			rectTab.X -= rectTab.Height / 2;
			rectTab.Intersect(TabsRectangle);
			rectTab = RectangleToScreen(DrawHelper.RtlTransform(this, rectTab));
			int y = rectTab.Top;
			Rectangle rectPaneClient = DockPane.RectangleToScreen(DockPane.ClientRectangle);

			GraphicsPath path = new GraphicsPath();
			GraphicsPath pathTab = GetTabOutline_Document(Tabs[index], true, true, true);
			path.AddPath(pathTab, true);
			path.AddLine(rectTab.Right, rectTab.Bottom, rectPaneClient.Right, rectTab.Bottom);
			path.AddLine(rectPaneClient.Right, rectTab.Bottom, rectPaneClient.Right, rectPaneClient.Bottom);
			path.AddLine(rectPaneClient.Right, rectPaneClient.Bottom, rectPaneClient.Left, rectPaneClient.Bottom);
			path.AddLine(rectPaneClient.Left, rectPaneClient.Bottom, rectPaneClient.Left, rectTab.Bottom);
			path.AddLine(rectPaneClient.Left, rectTab.Bottom, rectTab.Right, rectTab.Bottom);
			return path;
		}

		private GraphicsPath GetOutline_ToolWindow(int index)
		{
			Rectangle rectTab = GetTabRectangle(index);
			rectTab.Intersect(TabsRectangle);
			rectTab = RectangleToScreen(DrawHelper.RtlTransform(this, rectTab));
			int y = rectTab.Top;
			Rectangle rectPaneClient = DockPane.RectangleToScreen(DockPane.ClientRectangle);

			GraphicsPath path = new GraphicsPath();
			GraphicsPath pathTab = GetTabOutline(Tabs[index], true, true);
			path.AddPath(pathTab, true);
			//path.AddLine(rectTab.Left, rectTab.Top, rectPaneClient.Left, rectTab.Top);
			//path.AddLine(rectPaneClient.Left, rectTab.Top, rectPaneClient.Left, rectPaneClient.Top);
			//path.AddLine(rectPaneClient.Left, rectPaneClient.Top, rectPaneClient.Right, rectPaneClient.Top);
			//path.AddLine(rectPaneClient.Right, rectPaneClient.Top, rectPaneClient.Right, rectTab.Top);
			//path.AddLine(rectPaneClient.Right, rectTab.Top, rectTab.Right, rectTab.Top);
			return path;
		}

		private void CalculateTabs()
		{
			if (Appearance == DockPane.AppearanceStyle.ToolWindow)
				CalculateTabs_ToolWindow();
			else
				CalculateTabs_Document();
		}

		private void CalculateTabs_ToolWindow()
		{
			if (Tabs.Count <= 1 || DockPane.IsAutoHide)
				return;

			Rectangle rectTabStrip = TabStripRectangle;

			// Calculate tab widths
			int countTabs = Tabs.Count;
			foreach (PaneTab tab in Tabs)
			{
				tab.MaxWidth = GetMaxTabWidth(Tabs.IndexOf(tab));
				tab.Flag = false;
			}

			// Set tab whose max width less than average width
			bool anyWidthWithinAverage = true;
			int totalWidth = rectTabStrip.Width - ToolWindowStripGapLeft - ToolWindowStripGapRight;
			int totalAllocatedWidth = 0;
			int averageWidth = totalWidth / countTabs;
			int remainedTabs = countTabs;
			for (anyWidthWithinAverage = true; anyWidthWithinAverage && remainedTabs > 0; )
			{
				anyWidthWithinAverage = false;
				foreach (PaneTab tab in Tabs)
				{
					if (tab.Flag)
						continue;

					if (tab.MaxWidth <= averageWidth)
					{
						tab.Flag = true;
						tab.TabWidth = tab.MaxWidth;
						totalAllocatedWidth += tab.TabWidth;
						anyWidthWithinAverage = true;
						remainedTabs--;
					}
				}
				if (remainedTabs != 0)
					averageWidth = (totalWidth - totalAllocatedWidth) / remainedTabs;
			}

			// If any tab width not set yet, set it to the average width
			if (remainedTabs > 0)
			{
				int roundUpWidth = (totalWidth - totalAllocatedWidth) - (averageWidth * remainedTabs);
				foreach (PaneTab tab in Tabs)
				{
					if (tab.Flag)
						continue;

					tab.Flag = true;
					if (roundUpWidth > 0)
					{
						tab.TabWidth = averageWidth + 1;
						roundUpWidth--;
					}
					else
						tab.TabWidth = averageWidth;
				}
			}

			// Set the X position of the tabs
			int x = rectTabStrip.X + ToolWindowStripGapLeft;
			foreach (PaneTab tab in Tabs)
			{
				tab.TabX = x;
				x += tab.TabWidth;
			}
		}

		private bool CalculateDocumentTab(Rectangle rectTabStrip, ref int x, int index)
		{
			bool overflow = false;

			PaneTab tab = Tabs[index] as PaneTab;
			tab.MaxWidth = GetMaxTabWidth(index);
			int width = Math.Min(tab.MaxWidth, DocumentTabMaxWidth);
			if (x + width < rectTabStrip.Right || index == StartDisplayingTab)
			{
				tab.TabX = x;
				tab.TabWidth = width;
				EndDisplayingTab = index;
			}
			else
			{
				tab.TabX = 0;
				tab.TabWidth = 0;
				overflow = true;
			}
			x += width;

			return overflow;
		}

		private void CalculateTabs_Document()
		{
			if (_startDisplayingTab >= Tabs.Count)
				_startDisplayingTab = 0;

			Rectangle rectTabStrip = TabsRectangle;

			int x = rectTabStrip.X + 9; //rectTabStrip.Height / 2;

			bool overflow = false;
			for (int i = StartDisplayingTab; i < Tabs.Count; i++)
				overflow = CalculateDocumentTab(rectTabStrip, ref x, i);

			for (int i = 0; i < StartDisplayingTab; i++)
				overflow = CalculateDocumentTab(rectTabStrip, ref x, i);

			if (!overflow)
			{
				_startDisplayingTab = 0;
				x = rectTabStrip.X + 9; //rectTabStrip.Height / 2;
				foreach (PaneTab tab in Tabs)
				{
					tab.TabX = x;
					x += tab.TabWidth;
				}
			}
			DocumentTabsOverflow = overflow;
		}

		protected internal override void EnsureTabVisible(IDockContent content)
		{
			if (Appearance != DockPane.AppearanceStyle.Document || !Tabs.Contains(content))
				return;

			CalculateTabs();
			EnsureDocumentTabVisible(content, true);
		}

		private bool EnsureDocumentTabVisible(IDockContent content, bool repaint)
		{
			int index = Tabs.IndexOf(content);
			PaneTab tab = Tabs[index] as PaneTab;
			if (tab.TabWidth != 0)
				return false;

			StartDisplayingTab = index;
			if (repaint)
				Invalidate();

			return true;
		}

		private int GetMaxTabWidth(int index)
		{
			if (Appearance == DockPane.AppearanceStyle.ToolWindow)
				return GetMaxTabWidth_ToolWindow(index);
			else
				return GetMaxTabWidth_Document(index);
		}

		private int GetMaxTabWidth_ToolWindow(int index)
		{
			IDockContent content = Tabs[index].Content;
			Size sizeString = TextRenderer.MeasureText(content.DockHandler.TabText, TextFont);
			return ToolWindowImageWidth + sizeString.Width + ToolWindowImageGapLeft
				+ ToolWindowImageGapRight + ToolWindowTextGapRight;
		}

		private int GetMaxTabWidth_Document(int index)
		{
			IDockContent content = Tabs[index].Content;

			int height = GetTabRectangle_Document(index).Height;

			Size sizeText = TextRenderer.MeasureText(content.DockHandler.TabText, BoldFont, new Size(DocumentTabMaxWidth, height), DocumentTextFormat);

			if (DockPane.DockPanel.ShowDocumentIcon)
				return sizeText.Width + DocumentIconWidth + DocumentIconGapLeft + DocumentIconGapRight;// + DocumentTextGapRight;
			else
				return sizeText.Width + DocumentTextGapRight;
		}

		private void DrawTabStrip(Graphics g)
		{
			if (Appearance == DockPane.AppearanceStyle.Document)
				DrawTabStrip_Document(g);
			else
				DrawTabStrip_ToolWindow(g);
		}

		private void DrawTabStrip_Document(Graphics g)
		{
			int count = Tabs.Count;
			if (count == 0)
				return;

			Rectangle rectTabStrip = TabStripRectangle;

			// Draw the tabs
			Rectangle rectTabOnly = TabsRectangle;
			Rectangle rectTab = Rectangle.Empty;
			PaneTab tabActive = null;
			g.SetClip(DrawHelper.RtlTransform(this, rectTabOnly));
			for (int i = 0; i < count; i++)
			{
				rectTab = GetTabRectangle(i);
				if (Tabs[i].Content == DockPane.ActiveContent)
				{
					tabActive = Tabs[i] as PaneTab;
					continue;
				}
				if (rectTab.IntersectsWith(rectTabOnly))
					DrawTab(g, Tabs[i] as PaneTab, rectTab);
			}

			g.SetClip(rectTabStrip);
			g.DrawLine(PenDocumentTabActiveBorder, rectTabStrip.Left, rectTabStrip.Bottom - 1, rectTabStrip.Right - 1, rectTabStrip.Bottom - 1);
			g.SetClip(DrawHelper.RtlTransform(this, rectTabOnly));
			if (tabActive != null)
			{
				rectTab = GetTabRectangle(Tabs.IndexOf(tabActive));
				if (rectTab.IntersectsWith(rectTabOnly))
					DrawTab(g, tabActive, rectTab);
			}
		}

		private void DrawTabStrip_ToolWindow(Graphics g)
		{
			Rectangle rectTabStrip = TabStripRectangle;

			g.DrawLine(PenToolWindowTabBorder, rectTabStrip.Left, rectTabStrip.Top,
				rectTabStrip.Right, rectTabStrip.Top);

			for (int i = 0; i < Tabs.Count; i++)
				DrawTab(g, Tabs[i] as PaneTab, GetTabRectangle(i));
		}

		private Rectangle GetTabRectangle(int index)
		{
			if (Appearance == DockPane.AppearanceStyle.ToolWindow)
				return GetTabRectangle_ToolWindow(index);
			else
				return GetTabRectangle_Document(index);
		}

		private Rectangle GetTabRectangle_ToolWindow(int index)
		{
			Rectangle rectTabStrip = TabStripRectangle;

			PaneTab tab = (PaneTab)(Tabs[index]);
			return new Rectangle(tab.TabX, rectTabStrip.Y, tab.TabWidth, rectTabStrip.Height);
		}

		private Rectangle GetTabRectangle_Document(int index)
		{
			Rectangle rectTabStrip = TabStripRectangle;
			PaneTab tab = (PaneTab)Tabs[index];

			return new Rectangle(tab.TabX, rectTabStrip.Y + DocumentTabGapTop, tab.TabWidth, rectTabStrip.Height - DocumentTabGapTop);
		}

		private void DrawTab(Graphics g, PaneTab tab, Rectangle rect)
		{
			if (Appearance == DockPane.AppearanceStyle.ToolWindow)
				DrawTab_ToolWindow(g, tab, rect);
			else
				DrawTab_Document(g, tab, rect);
		}

		private GraphicsPath GetTabOutline(Tab tab, bool rtlTransform, bool toScreen)
		{
			return GetTabOutline(tab, rtlTransform, toScreen, true);
		}

		private GraphicsPath GetTabOutline(Tab tab, bool rtlTransform, bool toScreen, bool active)
		{
			if (Appearance == DockPane.AppearanceStyle.ToolWindow)
				return GetTabOutline_ToolWindow(tab, rtlTransform, toScreen, active);
			else
				return GetTabOutline_Document(tab, rtlTransform, toScreen, false);
		}

		private GraphicsPath GetTabOutline_ToolWindow(Tab tab, bool rtlTransform, bool toScreen, bool active)
		{
			Rectangle rect = GetTabRectangle(Tabs.IndexOf(tab));
			if (rtlTransform)
				rect = DrawHelper.RtlTransform(this, rect);
			if (toScreen)
				rect = RectangleToScreen(rect);

			GraphicsPath graphicsPath = GraphicsPath;
			if (graphicsPath == null)
				graphicsPath = new GraphicsPath();
			else
				graphicsPath.Reset();

			if (active)
			{
				rect.Height = rect.Height - 2;
				graphicsPath.AddRectangle(rect);
			}
			else
			{
				rect.Height = rect.Height - 4;
				graphicsPath.AddRectangle(rect);
			}

			return graphicsPath;
		}

		private GraphicsPath GetTabOutline_Document(Tab tab, bool rtlTransform, bool toScreen, bool full)
		{
			int curveSize = 6;

			GraphicsPath.Reset();
			Rectangle rect = GetTabRectangle(Tabs.IndexOf(tab));
			if (rtlTransform)
				rect = DrawHelper.RtlTransform(this, rect);
			if (toScreen)
				rect = RectangleToScreen(rect);

			bool active = false;
			if (tab.Content == DockPane.ActiveContent || Tabs.IndexOf(tab) == StartDisplayingTab || full)
			{
				active = (tab.Content == DockPane.ActiveContent);
				if (RightToLeft == RightToLeft.Yes)
				{
					GraphicsPath.AddLine(rect.Right, rect.Bottom, rect.Right + rect.Height / 2, rect.Bottom);
					GraphicsPath.AddLine(rect.Right + rect.Height / 2, rect.Bottom, rect.Right - rect.Height / 2 + curveSize / 2, rect.Top + curveSize / 2);
				}
				else
				{
					GraphicsPath.AddLine(rect.Left, rect.Bottom, rect.Left - rect.Height / 2, rect.Bottom);
					GraphicsPath.AddLine(rect.Left - rect.Height / 2, rect.Bottom, rect.Left + rect.Height / 2 - curveSize / 2, (rect.Top + curveSize / 2));
				}
			}
			else
			{
				if (RightToLeft == RightToLeft.Yes)
				{
					GraphicsPath.AddLine(rect.Right, rect.Bottom, rect.Right, rect.Bottom - rect.Height / 2);
					GraphicsPath.AddLine(rect.Right, rect.Bottom - rect.Height / 2, rect.Right - rect.Height / 2 + curveSize / 2, rect.Top + curveSize / 2);
				}
				else
				{
					GraphicsPath.AddLine(rect.Left, rect.Bottom, rect.Left, (rect.Bottom - rect.Height / 2));
					GraphicsPath.AddLine(rect.Left, rect.Bottom - rect.Height / 2, rect.Left + rect.Height / 2 - curveSize / 2, (rect.Top + curveSize / 2));
				}
			}

			if (RightToLeft == RightToLeft.Yes)
			{
				GraphicsPath.AddLine(rect.Right - rect.Height / 2 - curveSize / 2, rect.Top, rect.Left + curveSize / 2, rect.Top);
				GraphicsPath.AddArc(new Rectangle(rect.Left, rect.Top, curveSize, curveSize), 180, 90);
			}
			else
			{
				if (active)
				{
					GraphicsPath.AddLine(rect.Left + rect.Height / 2 + curveSize / 2, rect.Top, rect.Right - curveSize / 2, rect.Top);
					GraphicsPath.AddArc(new Rectangle(rect.Right - curveSize, rect.Top, curveSize, curveSize), -90, 90);
				}
				else
				{
					GraphicsPath.AddLine(rect.Left + rect.Height / 2 + curveSize / 2, rect.Top + 2, rect.Right - curveSize / 2, rect.Top + 2);
					GraphicsPath.AddArc(new Rectangle(rect.Right - curveSize, rect.Top + 2, curveSize, curveSize), -90, 90);
				}
			}

			if (Tabs.IndexOf(tab) != EndDisplayingTab &&
				(Tabs.IndexOf(tab) != Tabs.Count - 1 && Tabs[Tabs.IndexOf(tab) + 1].Content == DockPane.ActiveContent)
				&& !full)
			{
				if (RightToLeft == RightToLeft.Yes)
				{
					GraphicsPath.AddLine(rect.Left, rect.Top + curveSize / 2, rect.Left, rect.Top + rect.Height / 2);
					GraphicsPath.AddLine(rect.Left, rect.Top + rect.Height / 2, rect.Left + rect.Height / 2, rect.Bottom);
				}
				else
				{
					GraphicsPath.AddLine(rect.Right, rect.Top + curveSize / 2, rect.Right, rect.Top + rect.Height / 2);
					GraphicsPath.AddLine(rect.Right, rect.Top + rect.Height / 2, rect.Right - rect.Height / 2, rect.Bottom);
				}
			}
			else
			{
				if (RightToLeft == RightToLeft.Yes)
					GraphicsPath.AddLine(rect.Left, rect.Top + curveSize / 2, rect.Left, rect.Bottom);
				else
					GraphicsPath.AddLine(rect.Right, rect.Top + curveSize / 2, rect.Right, rect.Bottom);
			}

			return GraphicsPath;
		}

		private void DrawTab_ToolWindow(Graphics g, PaneTab tab, Rectangle rect)
		{
			Rectangle rectIcon = new Rectangle(
				rect.X + ToolWindowImageGapLeft,
				rect.Y + rect.Height - 3 - ToolWindowImageGapBottom - ToolWindowImageHeight,
				ToolWindowImageWidth, ToolWindowImageHeight);
			Rectangle rectText = rectIcon;
			rectText.X += rectIcon.Width + ToolWindowImageGapRight;
			rectText.Width = rect.Width - rectIcon.Width - ToolWindowImageGapLeft -
				ToolWindowImageGapRight - ToolWindowTextGapRight;

			Rectangle rectTab = DrawHelper.RtlTransform(this, rect);
			rectText = DrawHelper.RtlTransform(this, rectText);
			rectIcon = DrawHelper.RtlTransform(this, rectIcon);
			GraphicsPath path;

			if (DockPane.ActiveContent == tab.Content)
			{
				path = GetTabOutline(tab, true, false, true);
				g.FillPath(BrushToolWindowActiveBackground(rectTab), path);
				g.DrawPath(PenToolWindowTabBorder, path);
				TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, TextFont, rectText, ColorToolWindowActiveText, ToolWindowTextFormat);
			}
			else
			{
				path = GetTabOutline(tab, true, false, false);
				rectText.Y--;
				if (hoverIndex >= 0 && Tabs[hoverIndex] == tab)
				{
					Color fillColor1 = ControlPaint.LightLight(Color.SkyBlue);
					Color fillColor2 = Color.GhostWhite;
					using (LinearGradientBrush brush = new LinearGradientBrush(path.GetBounds(), fillColor1, fillColor2, LinearGradientMode.Vertical))
						g.FillPath(brush, path);
				}
				else
				{
					g.FillPath(BrushToolWindowInactiveBackground(rectTab), path);
				}
				g.DrawPath(PenToolWindowTabBorder, path);
				TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, TextFont, rectText, ColorToolWindowInactiveText, ToolWindowTextFormat);
			}

			if (rectTab.Contains(rectIcon))
				g.DrawIcon(tab.Content.DockHandler.Icon, rectIcon);
		}

		private void DrawTab_Document(Graphics g, PaneTab tab, Rectangle rect)
		{
			if (tab.TabWidth == 0)
				return;

			var rectIcon =
				new Rectangle(
					rect.X + DocumentIconGapLeft,
					rect.Y + rect.Height - DocumentIconGapBottom - DocumentIconHeight,
					DocumentIconWidth,
					DocumentIconHeight);

			var rectText =
					new Rectangle(
					rect.X + _DocumentTextGapLeft,
					rect.Y + rect.Y + 3,
					rect.Width - _DocumentTextGapRight,
					DocumentIconHeight);

			if (DockPane.DockPanel.ShowDocumentIcon)
			{
				rectText.X += rectIcon.Width + DocumentIconGapRight + 4;
				rectText.Width = rect.Width - rectIcon.Width - DocumentIconGapLeft - DocumentIconGapRight - DocumentTextGapRight;
			}

			var rectTab = DrawHelper.RtlTransform(this, rect);
			rectText = DrawHelper.RtlTransform(this, rectText);
			rectIcon = DrawHelper.RtlTransform(this, rectIcon);
			var path = GetTabOutline(tab, true, false);
			if (DockPane.ActiveContent == tab.Content)
			{
				rectIcon.X--;
				rectIcon.Y -= 2;
				rectText.Y -= 1;
				g.FillPath(DocTabActive_Brush(rectTab), path);
				g.DrawPath(PenDocumentTabActiveBorder, path);
				if (DockPane.IsActiveDocumentPane)
				{
					rectText.X += 2;
					TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, BoldFont, rectText, ColorDocumentActiveText, DocumentTextFormat);
				}
				else
				{
					rectText.X += 2;
					TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, TextFont, rectText, ColorDocumentActiveText, DocumentTextFormat);
				}
			}
			else
			{
				if (hoverIndex >= 0 && Tabs[hoverIndex] == tab)
				{
					Color fillColor1 = Color.GhostWhite;
					Color fillColor2 = ControlPaint.LightLight(Color.LightSkyBlue);

					using (LinearGradientBrush brush = new LinearGradientBrush(path.GetBounds(), fillColor1, fillColor2, LinearGradientMode.Vertical))
						g.FillPath(brush, path);

				}
				else
				{
					g.FillPath(DocTabInactive_Brush(rectTab), path);
				}

				g.DrawPath(PenDocumentTabInactiveBorder, path);
				TextRenderer.DrawText(g, tab.Content.DockHandler.TabText, TextFont, rectText, ColorDocumentInactiveText, DocumentTextFormat);
			}

			if (rectTab.Contains(rectIcon) && DockPane.DockPanel.ShowDocumentIcon)
				g.DrawIcon(tab.Content.DockHandler.Icon, rectIcon);
		}

		private Rectangle TabStripRectangle
		{
			get
			{
				if (Appearance == DockPane.AppearanceStyle.Document)
					return TabStripRectangle_Document;
				else
					return TabStripRectangle_ToolWindow;
			}
		}

		private Rectangle TabStripRectangle_ToolWindow
		{
			get
			{
				Rectangle rect = ClientRectangle;
				rect = new Rectangle(rect.X, rect.Top + ToolWindowStripGapTop, rect.Width, rect.Height - ToolWindowStripGapTop - ToolWindowStripGapBottom);
				return rect;
			}
		}

		private Rectangle TabStripRectangle_Document
		{
			get
			{
				Rectangle rect = ClientRectangle;
				int h = rect.Height - DocumentStripGapTop - DocumentStripGapBottom;
				return new Rectangle(rect.X, rect.Top + DocumentStripGapTop, rect.Width, h);
			}
		}

		private Rectangle TabsRectangle
		{
			get
			{
				if (Appearance == DockPane.AppearanceStyle.ToolWindow)
					return TabStripRectangle;

				Rectangle rectWindow = TabStripRectangle;
				int x = rectWindow.X;
				int y = rectWindow.Y;
				int width = rectWindow.Width;
				int height = rectWindow.Height;

				x += DocumentTabGapLeft;
				width -= DocumentTabGapLeft +
						DocumentTabGapRight +
						DocumentButtonGapRight +
						ButtonClose.Width +
						ButtonWindowList.Width +
						2 * DocumentButtonGapBetween;

				return new Rectangle(x, y, width, height);
			}
		}

		private ContextMenuStrip _selectMenu;
		private ContextMenuStrip SelectMenu
		{
			get { return _selectMenu; }
		}

		private void WindowList_Click(object sender, EventArgs e)
		{
			int x = 0;
			int y = ButtonWindowList.Location.Y + ButtonWindowList.Height;

			SelectMenu.Items.Clear();
			foreach (PaneTab tab in Tabs)
			{
				IDockContent content = tab.Content;
				ToolStripItem item = SelectMenu.Items.Add(content.DockHandler.TabText, content.DockHandler.Icon.ToBitmap());
				item.Tag = tab.Content;
				item.Click += new EventHandler(ContextMenuIte_Click);
			}
			SelectMenu.Show(ButtonWindowList, x, y);
		}

		private void ContextMenuIte_Click(object sender, EventArgs e)
		{
			ToolStripMenuItem item = sender as ToolStripMenuItem;
			if (item != null)
			{
				IDockContent content = (IDockContent)item.Tag;
				DockPane.ActiveContent = content;
			}
		}

		private void SetInertButtons()
		{
			if (Appearance == DockPane.AppearanceStyle.ToolWindow)
			{
				if (_buttonClose != null)
					_buttonClose.Left = -_buttonClose.Width;

				if (_buttonWindowList != null)
					_buttonWindowList.Left = -_buttonWindowList.Width;
			}
			else
			{
				bool showCloseButton = DockPane.ActiveContent == null ? true : DockPane.ActiveContent.DockHandler.CloseButton;
				ButtonClose.Enabled = showCloseButton;
				ButtonClose.RefreshChanges();
				ButtonWindowList.RefreshChanges();
			}
		}

		protected override void OnLayout(LayoutEventArgs levent)
		{
			if (Appearance != DockPane.AppearanceStyle.Document)
			{
				base.OnLayout(levent);
				return;
			}

			Rectangle rectTabStrip = TabStripRectangle;

			// Set position and size of the buttons
			int buttonWidth = ButtonClose.Image.Width;
			int buttonHeight = ButtonClose.Image.Height;
			int height = rectTabStrip.Height - DocumentButtonGapTop - DocumentButtonGapBottom;
			if (buttonHeight < height)
			{
				buttonWidth = buttonWidth * (height / buttonHeight);
				buttonHeight = height;
			}
			Size buttonSize = new Size(buttonWidth, buttonHeight);

			int x = rectTabStrip.X + rectTabStrip.Width - DocumentTabGapLeft
				- DocumentButtonGapRight - buttonWidth;
			int y = rectTabStrip.Y + DocumentButtonGapTop;
			Point point = new Point(x, y);
			ButtonClose.Bounds = DrawHelper.RtlTransform(this, new Rectangle(point, buttonSize));
			point.Offset(-(DocumentButtonGapBetween + buttonWidth), 0);
			ButtonWindowList.Bounds = DrawHelper.RtlTransform(this, new Rectangle(point, buttonSize));

			OnRefreshChanges();

			base.OnLayout(levent);
		}

		private void Close_Click(object sender, EventArgs e)
		{
			DockPane.CloseActiveContent();
		}

		protected internal override int HitTest(Point ptMouse)
		{
			Rectangle rectTabStrip = TabsRectangle;
			if (!TabsRectangle.Contains(ptMouse))
				return -1;

			foreach (Tab tab in Tabs)
			{
				GraphicsPath path = GetTabOutline(tab, true, false);
				if (path.IsVisible(ptMouse))
					return Tabs.IndexOf(tab);
			}
			return -1;
		}

		protected override void OnMouseHover(EventArgs e)
		{
			int index = HitTest(PointToClient(Control.MousePosition));
			string toolTip = string.Empty;

			base.OnMouseHover(e);

			if (index != -1)
			{
				PaneTab tab = Tabs[index] as PaneTab;
				if (!String.IsNullOrEmpty(tab.Content.DockHandler.ToolTipText))
					toolTip = tab.Content.DockHandler.ToolTipText;
				else if (tab.MaxWidth > tab.TabWidth)
					toolTip = tab.Content.DockHandler.TabText;
			}

			if (_toolTip.GetToolTip(this) != toolTip)
			{
				_toolTip.Active = false;
				_toolTip.SetToolTip(this, toolTip);
				_toolTip.Active = true;
			}

			// requires further tracking of mouse hover behavior,
			ResetMouseEventArgs();
		}

		protected override void OnRightToLeftChanged(EventArgs e)
		{
			base.OnRightToLeftChanged(e);
			PerformLayout();
		}

		protected override void OnMouseMove(MouseEventArgs e)
		{
			base.OnMouseMove(e);
			hoverIndex = HitTest(PointToClient(Control.MousePosition));
			Invalidate();
		}

		protected override void OnMouseLeave(EventArgs e)
		{
			base.OnMouseLeave(e);
			hoverIndex = -1;
			Invalidate();
		}

		int hoverIndex = -1;

	}
}